package com.zzl.mine.tool;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @description Java Calendar 类时间操作：获取时间，时间加减，以及比较时间大小等等。
 * @author rambo
 * @date 2018年5月23日 上午11:11:21
 */
@SuppressWarnings("ALL")
public class CalendarUtil {

	private final static Logger logger = LoggerFactory.getLogger(CalendarUtil.class);

	/**
	 * @description 显示年份
	 * @return
	 */
	public static int getYear(){
		return Calendar.getInstance().get(Calendar.YEAR);
	}

	/**
	 * @description 显示月份 (从0开始, 实际显示要加1)
	 * @return
	 */
	public static int getMonth(){
		return Calendar.getInstance().get(Calendar.MONTH) + 1;
	}

	/**
	 * @description 本月的第几天
	 * @return
	 */
	public static int getDayOfMonth(){
		return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * @description 本周几（星期几，礼拜几）
	 * @return
	 */
	public static String getDayOfWeek(){
		int dayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
		String day = "";
		switch (dayOfWeek){//int，short，char，byte
			case 1:
				day = "SUNDAY";//星期天（星期日）
				break;
			case 2:
				day = "MONDAY";//星期一
				break;
			case 3:
				day = "TUESDAY";//星期二
				break;
			case 4:
				day = "WEDNESDAY";//星期三
				break;
			case 5:
				day = "THURSDAY";//星期四
				break;
			case 6:
				day = "FRIDAY";//星期五
				break;
			default:
				day = "SATURDAY";//星期六
		}
		return day;
	}

	/**
	 * @description 今年的第几天
	 * @return
	 */
	public static int getDayOfYear(){
		return Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * @description 获取小时数
	 * @return
	 */
	public static int getHour(){
		return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @description n小时以后（获取的是小时，比如现在是18点，那么该方法就返回18+n点）
	 * @param n
	 * @return
	 */
	public static int getHourOfDayAfterN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, n);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @description n小时以前（获取的是小时，比如现在是18点，那么该方法就返回18-n点）
	 * @param n
	 * @return
	 */
	public static int getHourOfDayBeforeN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, unm(n));
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @description 获取分钟数
	 * @return
	 */
	public static int getMinute(){
		return Calendar.getInstance().get(Calendar.MINUTE);
	}

	/**
	 * @description n分钟以后（比如现在是38分，那么10分钟以后就是48分）
	 * @param n
	 * @return
	 */
	public static int getMinuteAfterN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, n);
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * @description n分钟以前（比如现在是38分，那么10分钟以前就是28分）
	 * @param n
	 * @return
	 */
	public static int getMinuteBeforeN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, unm(n));
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * @description 取整数的相反数
	 * @param num
	 * @return
	 */
	public static int unm(int num){
		return -num;
	}

	/**
	 * @description 格式化显示日期（日期转字符串）
	 * @param date
	 * @param regex 规则
	 * @return
	 */
	public static String dateToString(Date date, String regex){
		if(date != null){
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return new SimpleDateFormat(regex).format(calendar.getTime());
		}
		return "";
	}

	/**
	 * @description 格式化显示日期（日期转字符串）
	 * @param date
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static String dateToString(Date date){
		return dateToString(date, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @description 格式化显示日期（日期转字符串）
	 * @param date
	 * @param regex 规则
	 * @return
	 */
	public static String dateToStringAnother(Date date, String regex){
		return new SimpleDateFormat(regex).format(date);
	}

	/**
	 * @description 显示当前时间（字符串）
	 * @param regex 规则
	 * @return
	 */
	public static String getNowDate(String regex){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());//默认就是执行此方法，可以省略不写
		return new SimpleDateFormat(regex).format(calendar.getTime());
	}

	/**
	 * @description 显示当前时间（字符串）
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static String getNowDate(){
		return getNowDate("yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @description 显示当前时间（字符串）
	 * @param regex 规则
	 * @return
	 */
	public static String getNowDateAnother(String regex){
		return new SimpleDateFormat(regex).format(new Date());
	}

	/**
	 * @description 获取系统当前时间，其实就是new Date();
	 * @return
	 */
	public static Date getSystemCurrentDate() {
		return Calendar.getInstance().getTime();
	}
	
	/**
	 * @description 获取增加指定秒数后的时间
	 * @param second
	 * @return
	 */
	public static String getDateForAddSecond(Integer second){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date()); 
		calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) + second);
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime());
	}

	/**
	 * @description 根据日期规则将字符串转换为日期格式
	 * @param dateStr
	 * @param regex 规则（要和dateStr的格式一致）
	 * @return
	 */
	public static Date stringToDate(String dateStr, String regex){
		try {
			return new SimpleDateFormat(regex).parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			logger.info("日期格式转换异常："+dateStr+"和"+regex+"的格式不匹配");
			System.out.println("日期格式转换异常："+dateStr+"和"+regex+"的格式不匹配");
			logger.error("【字符串转日期失败，异常信息为】："+ e.getMessage());
			System.out.println("【字符串转日期失败，异常信息为】："+ e.getMessage());
		}
		return null;
	}

	/**
	 * @description 根据日期规则将字符串转换为日期格式
	 * @param dateStr
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static Date stringToDate(String dateStr){
		return stringToDate(dateStr, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @description 在只考虑yyyy-MM-dd和yyyy-MM-dd HH:mm:ss这两种情况下使用该方法，
	 * 		 当然了如果还有其他情况可以继续写判断！
	 * @param dateStr
	 * @return
	 */
	public static Date commonToDate(String dateStr) throws Exception{
		if(dateStr.length() == 10){
			return stringToDate(dateStr, "yyyy-MM-dd");
		}else if(dateStr.length() == 19){
			return stringToDate(dateStr);
		}
		return null;
	}

	/**
	 * @description 计算需要的时间
	 * @param date 原时间
	 * @param month 可以为null，为正数代表加，为负数代表减
	 * @param day 可以为null，为正数代表加，为负数代表减
	 * @param hour 可以为null，为正数代表加，为负数代表减
	 * @param minute 可以为null，为正数代表加，为负数代表减
	 * @param second 可以为null，为正数代表加，为负数代表减
	 * @return 返回加减后的时间
	 */
	public static Date getWantedDate(Date date, Integer month, Integer day, Integer hour, Integer minute, Integer second) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		if (null != month) {
			calendar.add(Calendar.MONTH, month);
		}
		if (null != day) {
			calendar.add(Calendar.DAY_OF_MONTH, day);
		}
		if (null != hour) {
			calendar.add(Calendar.HOUR_OF_DAY, hour);
		}
		if (null != minute) {
			calendar.add(Calendar.MINUTE, minute);
		}
		if (null != second) {
			calendar.add(Calendar.SECOND, second);
		}
		return calendar.getTime();
	}

	/**
	 * @description Date对象转Calendar对象
	 * @param date Date对象
	 * @return 返回Calendar对象
	 */
	public static Calendar dateToCalendar(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar;
	}
	
	/**
	 * @description 比较大小
	 * 后者大，显示 -1
	 * 前者大，显示 1
	 * 时间相同，显示 0
	 * @param date1 被比较时间
	 * @param date2 比较时间
	 * @return 如果被比较时间晚于比较时间返回1，否则返回-1
	 */
	public static int compare(Date date1, Date date2){
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(date1);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(date2);
		return calendar1.compareTo(calendar2);
	}

	/**
	 * @description 比较大小
	 * 后者大，显示 -1
	 * 前者大，显示 1
	 * 时间相同，显示 0
	 * @param date1 被比较时间
	 * @param regex1 规则
	 * @param date2 比较时间
	 * @param regex2 规则
	 * @return 如果被比较时间晚于比较时间返回1，否则返回-1
	 */
	public static int compare(String date1, String regex1, String date2, String regex2) {
		Date date11 = stringToDate(date1,regex1);
		Date date22 = stringToDate(date2,regex2);
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(date11);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(date22);
		return calendar1.compareTo(calendar2);
	}

	/**
	 * @description 获取当前系统时间（单位：毫秒）
	 * @return
	 */
	public static long getStartTime(){
		return System.currentTimeMillis();
	}

	/**
	 * @description 计算系统间隔时间（单位：秒）
	 * @param startTime 系统开始时间
	 * @return
	 */
	public static long interval(long startTime){
		long endTime = System.currentTimeMillis();
		return (endTime - startTime) / 1000;
	}

	/**
	 * @description 计算2个日期之间相隔的天数
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static int getDaysBetween(Calendar d1, Calendar d2) {
		if (d1.after(d2)) {//如果d1在d2后面，那么把两者的值进行互换，确保d2在d1的后面
			Calendar swap = d1;
			d1 = d2;
			d2 = swap;
		}
		int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
		int y2 = d2.get(Calendar.YEAR);
		if (d1.get(Calendar.YEAR) != y2) {
			d1 = (Calendar) d1.clone();
			do {
				days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);
				d1.add(Calendar.YEAR, 1);
			} while (d1.get(Calendar.YEAR) != y2);
		}
		return days;
	}

	/**
	 * @description 计算2个日期之间相隔的工作日天数
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static int getWorkingDay(Calendar d1, Calendar d2) {
		int result ;
		if (d1.after(d2)) {//如果d1在d2后面，那么把两者的值进行互换，确保d2在d1的后面
			Calendar swap = d1;
			d1 = d2;
			d2 = swap;
		}
		int charge_start_date = 0;//开始日期的日期偏移量
		int charge_end_date = 0;//结束日期的日期偏移量
		// 日期不在同一个日期内
		int stmp;
		int etmp;
		stmp = 7 - d1.get(Calendar.DAY_OF_WEEK);
		etmp = 7 - d2.get(Calendar.DAY_OF_WEEK);
		if (stmp != 0 && stmp != 6) {//开始日期为星期六和星期日时偏移量为0
			charge_start_date = stmp - 1;
		}
		if (etmp != 0 && etmp != 6) {//结束日期为星期六和星期日时偏移量为0
			charge_end_date = etmp - 1;
		}
		result = (getDaysBetween(getNextMonday(d1), getNextMonday(d2)) / 7)
				* 5 + charge_start_date - charge_end_date;
		return result;
	}

	/**
	 * @description 根据日期获知当天星期几
	 * @param date
	 * @return 返回中文星期几
	 */
	public static String getChineseWeek(Calendar date) {
		//1-星期日 2-星期一 3-星期二 4-星期三 5-星期四 6-星期五 7-星期六
		final String dayNames[] = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		int dayOfWeek = date.get(Calendar.DAY_OF_WEEK);
		return dayNames[dayOfWeek - 1];
	}

	/**
	 * @description 获得日期的下一个星期一的日期
	 * @param date
	 * @return
	 */
	public static Calendar getNextMonday(Calendar date) {
		Calendar result ;
		result = date;
		do {
			result = (Calendar) result.clone();
			result.add(Calendar.DATE, 1);
		} while (result.get(Calendar.DAY_OF_WEEK) != 2);
		return result;
	}

	/**
	 * @description 计算2个日期之间的休息日天数（只考虑周六周日不考虑节假日）
	 * @param d1 小日期
	 * @param d2 大日期
	 * @return
	 */
	public static int getOffDays(Calendar d1, Calendar d2){
		return getDaysBetween(d1, d2) - getWorkingDay(d1, d2);
	}

	/**
	 * @description 将日期时间中时间部分的:改成中文时分，最后加上秒
	 * @param dateTime 日期时间字符串
	 * @param h 时(点)
	 * @param m 分
	 * @param s 秒
	 * @return 返回结果比如：2017-07-05 11时28分06秒
	 */
	public static String convertDateTime2Zh(String dateTime, String h, String m, String s) {
		StringBuilder stringBuilder = new StringBuilder();

		//方法一：str.replaceFirst(a, b)只将字符串str中第一次出现的字符串a替换为字符串b
		//dateTime = dateTime.replaceFirst(":", h);
		//dateTime = dateTime.replaceFirst(":", m);

		//方法二：StringUtils.replaceOnce(str, a, b)只将字符串str中第一次出现的字符串a替换为字符串b
		dateTime = StringUtils.replaceOnce(dateTime, ":", h);
		dateTime = StringUtils.replaceOnce(dateTime, ":", m);

		//2017-07-05 11时28分06秒
		return stringBuilder.append(dateTime).append(s).toString();
	}

	/**
	 * @description 计算两个日期相差多少天小时分钟
	 * @param endDate 结束日期
	 * @param startDate 开始日期
	 * @return 返回相差时间的拼接字符串，比如2,3,4表示相差2天3小时4分钟
	 */
	public static Long[] getDatePoor(Date endDate, Date startDate) {
		Long oneMinute = 1000 * 60L;//1分钟
		Long oneHour = 1000 * 60 * 60L;//1小时
		Long oneDay = 1000 * 24 * 60 * 60L;//1天
		Long interval = endDate.getTime() - startDate.getTime();//获得两个时间的毫秒时间差异
		Long day = interval / oneDay;//计算差多少天
		Long hour = interval % oneDay / oneHour;//计算差多少小时
		Long minute = interval % oneDay % oneHour / oneMinute;//计算差多少分钟
		return new Long[]{day, hour, minute};
	}

	//==================================================【】=============================================

	/**
	 * @Description 获取指定日期的年月日
	 * @author houjie
	 * @param dateStr
	 * @param regex
	 * @return
	 */
	public static Map<String, Integer> getByDateStr(String dateStr, String regex){
		Date date = null;
		try {
			date = new SimpleDateFormat(regex).parse(dateStr);
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("日期格式转换异常：" + dateStr + "和" + regex + "的格式不匹配");
			System.out.println("日期格式转换异常：" + dateStr + "和" + regex + "的格式不匹配");
			logger.error("【字符串转日期失败，异常信息为】：" + e.getMessage());
			System.out.println("【字符串转日期失败，异常信息为】：" + e.getMessage());
		}
		Calendar ca = Calendar.getInstance();
		ca.setTime(date);
		Map<String, Integer> map = new HashMap<String, Integer>();
		int day = ca.get(Calendar.DAY_OF_YEAR);//一年中的第几天
		int week = ca.get(Calendar.WEEK_OF_YEAR) + 1;//一年中的第几周
		int month = ca.get(Calendar.MONTH) + 1;//第几个月
		int year = ca.get(Calendar.YEAR);//年份数值
		map.put("day", day);
		map.put("week", week);
		map.put("month", month);
		map.put("year", year);
		return map;
	}
	
	/**
	 * @Description 获取两个日期之间所有的月份或年
	 * @author houjie
	 * @param minDate
	 * @param maxDate
	 * @param regex
	 * @return
	 */
	public static List<String> getMonthBetween(String minDate, String maxDate, String regex) {
		ArrayList<String> result = new ArrayList<String>();
		SimpleDateFormat sdf = new SimpleDateFormat(regex);//格式化为年月
		 
		Calendar min = Calendar.getInstance();
		Calendar max = Calendar.getInstance();
		
		try {
			min.setTime(sdf.parse(minDate));
			max.setTime(sdf.parse(maxDate));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		if("yyyy-MM-dd".equals(regex)){
			min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), min.get(Calendar.DATE));
			max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), max.get(Calendar.DATE)+1);
		}else{
			min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
			max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
		}
		
		Calendar curr = min;
		while (curr.before(max)) {
			result.add(sdf.format(curr.getTime()));
			if("yyyy-MM".equals(regex)){
				curr.add(Calendar.MONTH, 1);
			}else if("yyyy".equals(regex)){
				curr.add(Calendar.YEAR, 1);
			}else if("yyyy-MM-dd".equals(regex)){
				curr.add(Calendar.DATE, 1);
			}
		}
		
		return result;
	}
	
	/**
	 * @Description 获取当前时间是周几（周日是一周的第一天）
	 * @author houjie
	 * @param datetime
	 * @return
	 */
	 public static int dateToWeek(String datetime) {
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        Date datet = null;
        try {
            datet = f.parse(datetime);
            cal.setTime(datet);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0)
            w = 0;
        return w;
    }
	 
	/**
	 * @Description 判断两个日期是否在同一周
	 * @author houjie
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static boolean isSameDate(String date1, String date2){
		 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		 Date d1 = null;
		 Date d2 = null;
		 try{
			 d1 = format.parse(date1);
			 d2 = format.parse(date2);
		 }catch (Exception e){
			 e.printStackTrace();
		 }
		 Calendar cal1 = Calendar.getInstance();
		 Calendar cal2 = Calendar.getInstance();
		 cal1.setFirstDayOfWeek(Calendar.SUNDAY);//西方周日为一周的第一天
		 cal2.setFirstDayOfWeek(Calendar.SUNDAY);
		 cal1.setTime(d1);
		 cal2.setTime(d2);
		 int subYear = cal1.get(Calendar.YEAR) - cal2.get(Calendar.YEAR);
		 if (subYear == 0){
			 if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)){
				 return true;
			 }
		 }else if (subYear == 1 && cal2.get(Calendar.MONTH) == 11){
			 if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)){
				 return true;
			 }
		 }else if (subYear == -1 && cal1.get(Calendar.MONTH) == 11){
			 if (cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR)){
				 return true;
			 }
		 }
		 return false;
	}
	
	/**
	 * @Description 获取当月第一天日期
	 * @author houjie
	 * @param regex
	 * @return
	 */
	public static String getFirstDayByMonth(String regex){
		 SimpleDateFormat format = new SimpleDateFormat(regex); 
		Calendar c = Calendar.getInstance();    
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天 
        String first = format.format(c.getTime());
        return first;
	}
	
	/**
	 * 获取当前日期是星期几
	 * @param date
	 * @return 当前日期是星期几
	 */
	public static String getWeekOfDate(Date date) {
		String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (w < 0)
			w = 0;
		return weekDays[w];
	}
	
	/**
	 * @Description 获取UTC格式时间
	 * @return
	 */
	public static String getUTCDate() {
        String dateStr = "";
        Date date = null;
        String months = "", days = "", hours = "", sec = "", minutes = "";
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        StringBuffer UTCTimeBuffer = new StringBuffer();
        Calendar cal = Calendar.getInstance();
        int zoneOffset = cal.get(java.util.Calendar.ZONE_OFFSET);
        int dstOffset = cal.get(java.util.Calendar.DST_OFFSET);
        cal.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        if (month < 10) {
            months = "0" + String.valueOf(month);
        }
        else {
            months = String.valueOf(month);
        }
        if (minute < 10) {
            minutes = "0" + String.valueOf(minute);
        }
        else {
            minutes = String.valueOf(minute);
        }
        if (day < 10) {
            days = "0" + String.valueOf(day);
        }
        else {
            days = String.valueOf(day);
        }
        if (hour < 10) {
            hours = "0" + String.valueOf(hour);
        }
        else {
            hours = String.valueOf(hour);
        }
        if (second < 10) {
            sec = "0" + String.valueOf(second);
        }
        else {
            sec = String.valueOf(second);
        }
        UTCTimeBuffer.append(year).append("-").append(months).append("-").append(days);
        UTCTimeBuffer.append("T").append(hours).append(":").append(minutes).append(":").append(sec).append("Z");
        try {
            date = format.parse(UTCTimeBuffer.toString());
            dateStr = format.format(date);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return dateStr;
    }
	
	public static void main(String[] args) {
		System.out.println(getFirstDayByMonth("yyyy-MM-dd"));
	}
}
